<template>
  <div class="wrapper">
    <a-affix :offset-top="10">
      <a-button v-if="applyDisplay" @click="onApply" type="danger"
        >应用</a-button
      >
    </a-affix>

    <div class="container">
      <a-card title="列" class="columns card-item">
        <div class="content">
          <draggable
            :move="onMove"
            :sort="false"
            class="drag"
            :list="fields"
            :group="{ name: 'src', pull: 'clone', put: false }"
            item-key="field"
            :clone="onSrcClone"
          >
            <template #item="{ element }">
              <div>
                <a-popover title="详细信息" trigger="click">
                  <a-tag color="processing">{{ element.label }}</a-tag>
                </a-popover>
              </div>
            </template>
          </draggable>
        </div>
      </a-card>

      <a-card title="分组keys" class="keys card-item">
        <div class="content">
          <draggable
            :move="onMove"
            class="drag"
            :list="groupKeys"
            group="src"
            item-key="__key"
          >
            <template #item="{ element }">
              <div>
                <a-tag
                  color="success"
                  closable
                  @close="onGroupKeysTagClose(element.__key)"
                  >{{ element.title }}</a-tag
                >
              </div>
            </template>
          </draggable>
        </div>
      </a-card>

      <a-card title="聚合" class="agg card-item">
        <div class="content">
          <draggable
            @add="onAggAdded"
            class="drag"
            :list="aggFields"
            group="src"
            item-key="__key"
          >
            <template #item="{ element }">
              <div>
                <a-tag
                  style="width: 80%"
                  color="success"
                  closable
                  @close="onAggTagClose(element.__key)"
                  >{{ element.title }} <span>：</span>
                  <a-select
                    v-model:value="selectOptsMapping[element.__key]"
                    mode="multiple"
                    style="width: 50%"
                    placeholder="选择聚合方式"
                    option-label-prop="label"
                  >
                    <a-select-option
                      v-for="opt in opts[element.type]"
                      :value="opt"
                      :label="opt"
                      :key="opt"
                    >
                      {{ opt }}
                    </a-select-option>
                  </a-select>
                </a-tag>
              </div>
            </template>
          </draggable>
        </div>
      </a-card>
    </div>
  </div>
</template>

<script lang='ts'>
import {
  computed,
  defineComponent,
  reactive,
  Ref,
  ref,
  toRaw,
  toRef,
} from "vue";
import draggable from "vuedraggable";

import DfStore from "@/store/DfStore";
import * as apps from "@/applications";
import { GroupbyModel } from "@/models/GroupbyModel";
import { ColumnInfo, ColumnInfoItem, Field } from "@/models/DataFrameModel";

let globalGroupKys = 0;

export default defineComponent({
  name: "Groupby",
  components: { draggable },
  setup() {
    let fields = DfStore.getStateToRefs().columnInfo;

    let groupKeys = ref([] as Array<Field>);
    let aggFields = ref([] as Array<Field>);
    let selectOptsMapping = ref({} as { [key: string]: Ref<string[]> });
    let selectOptsField = ref({} as { [key: string]: string });

    let applyDisplay = computed(() => {
      let has_selected = Object.values(selectOptsMapping.value).some(
        (v) => (v as Array<string>).length > 0
      );

      return groupKeys.value.length > 0 && has_selected;
    });

    let opts = {
      str: ["first", "last", "sum"],
      number: ["first", "last", "sum", "mean"],
    };

    let onGroupKeysTagClose = (keyIdx: string) => {
      let idx = groupKeys.value.findIndex((v: any) => v.__key === keyIdx);
      groupKeys.value.splice(idx, 1);
    };

    let onAggTagClose = (keyIdx: string) => {
      let idx = aggFields.value.findIndex((v: any) => v.__key === keyIdx);
      aggFields.value.splice(idx, 1);

      delete selectOptsMapping.value[keyIdx];
      delete selectOptsField.value[keyIdx];
    };

    let onSrcClone = (obj: ColumnInfoItem) => {
      return {
        field: obj.field,
        title: obj.label,
        type: obj.ui_type,
        __key: (globalGroupKys++).toString(),
      };
    };

    let onAggAdded = (e: any) => {
      let f = aggFields.value[e.newIndex] as any;

      let tmp = selectOptsMapping.value as any;
      tmp = ref([]);
      selectOptsField.value[f.__key] = f.field;
    };

    let onMove = (evt: any, originalEvent: any) => {
      if (evt.relatedContext.list === groupKeys.value) {
        return true;
      }

      if (evt.relatedContext.list === aggFields.value) {
        let f = fields.value[evt.draggedContext.index];
        return Object.values(selectOptsField.value).indexOf(f.field) < 0;
      }
    };

    let onApply = async () => {
      let model = new GroupbyModel();

      let keys = groupKeys.value.map((v: any) => v.field);
      model.setKeys(keys);

      Object.keys(selectOptsField.value).map((v) => {
        model.addAggs(
          selectOptsField.value[v],
          Object.values(selectOptsMapping.value[v])
        );
      });

      await apps.GroupByPandas(model);

      groupKeys.value = [];
      aggFields.value = [];
      selectOptsMapping.value = {};
      selectOptsField.value = {};
    };

    return {
      groupKeys,
      aggFields,
      fields,
      onGroupKeysTagClose,
      onAggTagClose,
      onSrcClone,
      selectOptsMapping,
      opts,
      onAggAdded,
      onApply,
      selectOptsField,
      onMove,
      applyDisplay,
    };
  },
});
</script>


<style lang='less' scoped>
.card-item {
  margin: 5px;
  background-color: rgb(250 250 250);
}

.columns div.drag {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  align-content: flex-start;
  // min-height: 10vh;
  max-height: 15vh;
  overflow: auto;

  > div {
    // margin-left: 1px;
    margin: 2px;
    // margin-top: 2px;
  }
}
.get_drag() {
  div.drag {
    min-height: 5vh;
    // max-height: 25vh;
    overflow: auto;

    > div {
      margin-bottom: 2px;
    }
  }
}

.keys {
  .get_drag();
}

.agg {
  .get_drag();
}

div.apply-btn {
  width: 200px;
  margin: 0 auto;
}

div.container {
  display: flex;
  flex-direction: row;
  align-items: flex-start;

  // height: 20vh;

  > div {
    &.columns {
      flex-grow: 0.5;
    }

    &.keys {
      flex-grow: 0;
    }

    &.agg {
      flex-grow: 0.5;
    }
  }
}
</style>